// *******************************************************
// >> File Name: /home/diabio/project/al_cache/al_cache/fifo_cache.h
// >> Author: diabiolin
// >> Created Time: Thu 24 Apr 2025 11:12:26 PM CST
// >> Description:
// *******************************************************
#pragma once
#include "cache_policy.h"
#include <unordered_map>
#include <queue>
#include <utility>
#include <mutex>
#include <memory>

namespace al_cache{

template <typename Key, typename Value>
class FifoCache : public CachePolicy<Key, Value>{
public:
	using NodePtr = std::shared_ptr<std::pair<Key, Value>>;
    FifoCache(int capacity)
        : capacity_(capacity)
        {};
	
	~FifoCache() override = default;

    void put(Key key, Value value) override {
    	if(capacity_ <= 0){
			return;
		}
		std::lock_guard<std::mutex> lock(mutex_);
		auto it = cacheMap_.find(key);
		if(it != cacheMap_.end()){
			it->second->second = value;
			return;
		}

		if(cacheMap_.size() >= capacity_){
			rmEarliest();
		}

		NodePtr newNode = std::make_shared<std::pair<Key, Value>> (key, value);
		cacheMap_[key] = newNode;
		cacheQueue_.push(newNode);
    }

	// 查找缓存
    bool get(Key key, Value &value) override {
    	std::lock_guard<std::mutex> lock(mutex_);
		auto it = cacheMap_.find(key);
		if(it != cacheMap_.end()){
			value = it->second->second;
			return true;
		}
		return false;
    }

    Value get(Key key) override {
    	Value value{};
		get(key, value);
		return value;
    }

private:
    int capacity_;
    std::unordered_map<Key, NodePtr> cacheMap_;  // key -> NodePtr
    std::queue<NodePtr> cacheQueue_;  // 记录插入的顺序
    std::mutex mutex_;  // 保护 cacheMap_ 和 cacheQueue_

    // 私有方法
  	// 移除最早插入元素
	void rmEarliest(){
		if(cacheQueue_.empty()){
			return;
		}
		NodePtr earliestNode = cacheQueue_.front();
		cacheQueue_.pop();
		cacheMap_.erase(earliestNode->first);
	} 
};


} // namespace al_cache

